/*!
    \file    change log.txt
    \brief   change log for GD32E502 firmware

    \version 2025-08-09, V1.6.0, firmware for GD32E502
*/

/*
    Copyright (c) 2024, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

******************* V1.6.0 2025-08-09 ******************************************************************************************
______________________Common______________________________________________________________________________________________

________________________________________________________________________________________________________________________

________________________Module I2C _______________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_i2c.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_i2c.h

fix reason:
The NACKEN bit of I2C cannot be cleared by software. Remove void i2c_nack_disable(uint32_t i2c_periph).

V1.5.0:
void i2c_nack_disable(uint32_t i2c_periph)
{
    I2C_CTL1(i2c_periph) &= ~I2C_CTL1_NACKEN;
}
 
V1.6.0:
none

fix reason:
Change the i2c_transfer_byte_number_config parameter to uint8.

V1.5.0:
void i2c_transfer_byte_number_config(uint32_t i2c_periph, uint32_t byte_number)
{
    I2C_CTL1(i2c_periph) &= (uint32_t)(~I2C_CTL1_BYTENUM);
    I2C_CTL1(i2c_periph) |= (uint32_t)(byte_number << CTL1_BYTENUM_OFFSET);
}
 
V1.6.0:
void i2c_transfer_byte_number_config(uint32_t i2c_periph, uint8_t byte_number)
{
    I2C_CTL1(i2c_periph) &= (uint32_t)(~I2C_CTL1_BYTENUM);
    I2C_CTL1(i2c_periph) |= (uint32_t)((uint32_t)byte_number << CTL1_BYTENUM_OFFSET);
}
__________________________________________________________________________________________________________________________

________________________Module SYSCFG _______________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_syscfg.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_syscfg.h

fix reason:
Upgrade the chip part number from version B to version E and remove the SRAM boot function. Delete the corresponding content of the BOOT_MODE bit field. Remove the SYSCFG_BOOTMODE_SRAM macro.

V1.5.0:
#define SYSCFG_CFG0_BOOT_MODE                          BITS(0,1)
#define SYSCFG_CFG0_BOOTMODE_MASK                (uint8_t)0x03U

V1.6.0:
#define SYSCFG_CFG0_BOOT_MODE                          BIT(0)
#define SYSCFG_CFG0_BOOTMODE_MASK                (uint8_t)0x01U
__________________________________________________________________________________________________________________________

______________________Module USART_________________________________________________________________________________________________
Fix file:
../Examples/USART/Half_duplex_transmitter&receiver/main.c

fix reason:
In the USART half-duplex communication mode, the TX pin has been modified from open-drain output mode to open-drain mode.


V1.5.0:
void com_usart_init(void)
{
	......

    /* configure USART0 TX as alternate function push-pull */
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_12);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_12);

    /* configure USART1 TX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_10);
    
	......

}

V1.6.0:
void com_usart_init(void)
{
	......

    /* configure USART0 TX as alternate function open-drain */
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_12);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_PIN_12);

    /* configure USART1 TX as alternate function open-drain */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_PIN_10);
    
	......

}
__________________________________________________________________________________________________________________________


______________________Module RTC_________________________________________________________________________________________________
Fix file:
../Examples/RCU/System_clock_switch/main.c

fix reason:
Ensure that the BKPRST bit is cleared before reading the backup domain registers.

V1.5.0:
int main(void)
{

	......

    printf("\r\n This is a RTC demo...... \r\n");

    /* get RTC clock entry selection */
    RTCSRC_FLAG = GET_BITS(RCU_BDCTL, 8, 9);
	......

}

V1.6.0:
int main(void)
{

	......

    /* enable PMU and BKPI clocks */
    rcu_periph_clock_enable(RCU_BKP);
    rcu_periph_clock_enable(RCU_PMU);
    /* allow access to BKP domain */
    pmu_backup_write_enable();
    if(RESET != (RCU_BDCTL & RCU_BDCTL_BKPRST)) {
        rcu_bkp_reset_disable();
    }

    printf("\r\n This is a RTC demo...... \r\n");

    /* get RTC clock entry selection */
    RTCSRC_FLAG = GET_BITS(RCU_BDCTL, 8, 9);

	......

}
__________________________________________________________________________________________________________________________

______________________Module DBG_________________________________________________________________________________________________
Fix file:
../Examples/DBG/DBG_timer1_stop/main.c

fix reason:
Modify the timer settings in the DBG example.

V1.5.0:
void timer_configuration(void)
{

	......

    /* CH1,CH2 and CH3 configuration in PWM mode */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate =  TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

	......

}

V1.6.0:
void timer_configuration(void)
{

	......

    /* CH1,CH2 and CH3 configuration in PWM mode */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_LOW;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate =  TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

	......

}
__________________________________________________________________________________________________________________________

******************* V1.5.0 2025-02-10 ******************************************************************************************
______________________Common______________________________________________________________________________________________
Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Add a software delay when the MCU switches to the IRC8M clock source.

V1.4.0:
none
 
V1.5.0:
void SystemInit(void)
{
	......

    RCU_CFG0 &= ~RCU_CFG0_SCS;
    _soft_delay_(100);

	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_8m_irc8m(void)
{
	......

    /* select IRC8M as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_IRC8M;
	......

}
 
V1.5.0:
								  
static void system_clock_8m_irc8m(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select IRC8M as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_IRC8M;
    RCU_CFG0 = reg_temp;
	......

}

Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_24m_pll_irc8m(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_24m_pll_irc8m(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_48m_pll_irc8m(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_48m_pll_irc8m(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_72m_pll_irc8m(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_72m_pll_irc8m(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_100m_pll_irc8m(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_100m_pll_irc8m(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_hxtal(void)
{
	......

    /* select HXTAL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_HXTAL;
	......

}
 
V1.5.0:
								  
static void system_clock_hxtal(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select HXTAL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_HXTAL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_24m_pll_hxtal(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_24m_pll_hxtal(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_48m_pll_hxtal(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_48m_pll_hxtal(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_72m_pll_hxtal(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_72m_pll_hxtal(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Use the new read-modify-write method to configure registers for clock source switching.

V1.4.0:
static void system_clock_100m_pll_hxtal(void)
{
	......

    /* select PLL as system clock */
    RCU_CFG0 &= ~RCU_CFG0_SCS;
    RCU_CFG0 |= RCU_CKSYSSRC_PLL;
	......

}
 
V1.5.0:
								  
static void system_clock_100m_pll_hxtal(void)
{
	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;
	......

}
________________________________________________________________________________________________________________________

________________________Module FMC _______________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.h

fix reason:
Remove the macro for a data flash size of 16K (OB1CS_DF_16K).

V1.4.0:
#define OB1CS_DF_16K                 OB1CS_EFALC_EPSIZE((uint8_t)0xF2U)
 
V1.5.0:
none

__________________________________________________________________________________________________________________________

________________________Module CAN _______________________________________________________________________________________
Fix file:
../Examples/CAN/communication_FDmode/main.c

fix reason:
The transmission delay compensation value exceeds the configurable range of the register. In the example, disable the transmission delay compensation feature for CANFD frames.

V1.4.0:
fd_parameter.tdc_enable = ENABLE;
fd_parameter.tdc_offset = 40;

V1.5.0:
fd_parameter.tdc_enable = DISABLE;
fd_parameter.tdc_offset = 0;

__________________________________________________________________________________________________________________________

______________________Module misc_________________________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_misc.c
fix reason:
1. Change the parameter type of nvic_irq to the IRQn_Type enumeration.
2. Add a check for the range of the nvic_irq parameter within the function.


V1.4.0:
void nvic_irq_enable(uint8_t nvic_irq, uint8_t nvic_irq_pre_priority,
                     uint8_t nvic_irq_sub_priority)
{
    uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;
    /* use the priority group value to get the temp_pre and the temp_sub */
    if(((SCB->AIRCR) & (uint32_t)0x700U) == NVIC_PRIGROUP_PRE0_SUB4) {
        temp_pre = 0U;
        temp_sub = 0x4U;
    } else if(((SCB->AIRCR) & (uint32_t)0x700U) == NVIC_PRIGROUP_PRE1_SUB3) {
        temp_pre = 1U;
        temp_sub = 0x3U;
    } else if(((SCB->AIRCR) & (uint32_t)0x700U) == NVIC_PRIGROUP_PRE2_SUB2) {
        temp_pre = 2U;
        temp_sub = 0x2U;
    } else if(((SCB->AIRCR) & (uint32_t)0x700U) == NVIC_PRIGROUP_PRE3_SUB1) {
        temp_pre = 3U;
        temp_sub = 0x1U;
    } else if(((SCB->AIRCR) & (uint32_t)0x700U) == NVIC_PRIGROUP_PRE4_SUB0) {
        temp_pre = 4U;
        temp_sub = 0x0U;
    } else {
        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
        temp_pre = 2U;
        temp_sub = 0x2U;
    }
    /* get the temp_priority to fill the NVIC->IP register */
    temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
    temp_priority |= (uint32_t)nvic_irq_sub_priority & ((uint32_t)0x0FU >> (0x4U - temp_sub));
    temp_priority = temp_priority << 0x04U;
    NVIC->IPR[nvic_irq] = (uint8_t)temp_priority;
    /* enable the selected IRQ */
    NVIC->ISER[nvic_irq >> 0x05U] = (uint32_t)0x01U << (nvic_irq & (uint8_t)0x1FU);
}

 
V1.5.0:
void nvic_irq_enable(IRQn_Type nvic_irq, uint8_t nvic_irq_pre_priority, 
                     uint8_t nvic_irq_sub_priority)
{
    if((int)nvic_irq < 0) {
        /* do nothing, should not be here */
    } else {
        uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;
        /* use the priority group value to get the temp_pre and the temp_sub */
        if(((SCB->AIRCR) & (uint32_t)0x700U)==NVIC_PRIGROUP_PRE0_SUB4){
            temp_pre=0U;
            temp_sub=0x4U;
        }else if(((SCB->AIRCR) & (uint32_t)0x700U)==NVIC_PRIGROUP_PRE1_SUB3){
            temp_pre=1U;
            temp_sub=0x3U;
        }else if(((SCB->AIRCR) & (uint32_t)0x700U)==NVIC_PRIGROUP_PRE2_SUB2){
            temp_pre=2U;
            temp_sub=0x2U;
        }else if(((SCB->AIRCR) & (uint32_t)0x700U)==NVIC_PRIGROUP_PRE3_SUB1){
            temp_pre=3U;
            temp_sub=0x1U;
        }else if(((SCB->AIRCR) & (uint32_t)0x700U)==NVIC_PRIGROUP_PRE4_SUB0){
            temp_pre=4U;
            temp_sub=0x0U;
        }else{
            nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
            temp_pre=2U;
            temp_sub=0x2U;
        }
        /* get the temp_priority to fill the NVIC->IP register */
        temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
        temp_priority |= (uint32_t)nvic_irq_sub_priority &((uint32_t)0x0FU >> (0x4U - temp_sub));
        temp_priority = temp_priority << 0x04U;
        NVIC->IPR[(uint8_t)nvic_irq] = (uint8_t)temp_priority;
        /* enable the selected IRQ */
        NVIC->ISER[(uint8_t)nvic_irq >> 0x05U] = (uint32_t)0x01U << ((uint8_t)nvic_irq & (uint8_t)0x1FU);
    }
}
__________________________________________________________________________________________________________________________


______________________Module RCU_________________________________________________________________________________________________
Fix file:
../Examples/RCU/System_clock_switch/main.c

fix reason:
1. Use the new read-modify-write method to configure registers for clock source switching.
2. Add a three-step frequency switching function in both increasing and decreasing frequency stages.

V1.4.0:
none

V1.5.0:
static void switch_system_clock_to_72m_hxtal(void)
{

	......
    if(((RCU_CFG0 & RCU_CFG0_SCSS) == RCU_SCSS_PLL)){
        /* It is strongly recommended to use it to avoid issues caused by self-removal. */
        /* stepwise frequency reduction */
        RCU_MODIFY_DE_3(50);
    }
    /* select IRC8M as system clock source, deinitialize the RCU */
    rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
    /* It is strongly recommended to use it to avoid issues caused by self-removal. */
    _soft_delay_(100);

	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;

    /* wait until PLL is selected as system clock */
    while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
    }
    /* It is strongly recommended to use it to avoid issues caused by self-removal. */
    RCU_MODIFY_UP_3(50);

	......

}


fix reason:
1. Use the new read-modify-write method to configure registers for clock source switching.
2. Add a three-step frequency switching function in both increasing and decreasing frequency stages.

V1.4.0:
none

V1.5.0:
static void switch_system_clock_to_100m_irc8m(void)
{

	......
    if(((RCU_CFG0 & RCU_CFG0_SCSS) == RCU_SCSS_PLL)){
        /* It is strongly recommended to use it to avoid issues caused by self-removal. */
        RCU_MODIFY_DE_3(50);
    }
    /* select IRC8M as system clock source, deinitialize the RCU */
    rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
    /* It is strongly recommended to use it to avoid issues caused by self-removal. */
    _soft_delay_(100);

	......

    reg_temp = RCU_CFG0;
    /* select PLL as system clock */
    reg_temp &= ~RCU_CFG0_SCS;
    reg_temp |= RCU_CKSYSSRC_PLL;
    RCU_CFG0 = reg_temp;

    /* wait until PLL is selected as system clock */
    while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
    }
    /* It is strongly recommended to use it to avoid issues caused by self-removal. */
    RCU_MODIFY_UP_3(50);

	......

}
__________________________________________________________________________________________________________________________


******************* V1.4.0 2024-12-13 ******************************************************************************************
______________________Common______________________________________________________________________________________________
Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Add a three-step frequency switching function in the system_gd32e502.c file for both increasing and decreasing frequency stages.

V1.3.0:
none
 
V1.4.0:
#define RCU_MODIFY_DE_3(__delay)  do{                                     \
                                      volatile uint32_t i,reg;            \
                                      if(0 != __delay){                   \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                          reg = RCU_CFG0;                 \
                                          reg &= ~(RCU_CFG0_AHBPSC);      \
                                          reg |= RCU_AHB_CKSYS_DIV2;      \
                                          RCU_CFG0 = reg;                 \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                          reg = RCU_CFG0;                 \
                                          reg &= ~(RCU_CFG0_AHBPSC);      \
                                          reg |= RCU_AHB_CKSYS_DIV4;      \
                                          RCU_CFG0 = reg;                 \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                          reg = RCU_CFG0;                 \
                                          reg &= ~(RCU_CFG0_AHBPSC);      \
                                          reg |= RCU_AHB_CKSYS_DIV8;      \
                                          RCU_CFG0 = reg;                 \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                      }                                   \
                                  }while(0)

#define RCU_MODIFY_UP_3(__delay)  do{                                     \
                                      volatile uint32_t i,reg;            \
                                      if(0 != __delay){                   \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                          reg = RCU_CFG0;                 \
                                          reg &= ~(RCU_CFG0_AHBPSC);      \
                                          reg |= RCU_AHB_CKSYS_DIV4;      \
                                          RCU_CFG0 = reg;                 \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                          reg = RCU_CFG0;                 \
                                          reg &= ~(RCU_CFG0_AHBPSC);      \
                                          reg |= RCU_AHB_CKSYS_DIV2;      \
                                          RCU_CFG0 = reg;                 \
                                          for(i=0; i<__delay; i++){       \
                                          }                               \
                                          reg = RCU_CFG0;                 \
                                          reg &= ~(RCU_CFG0_AHBPSC);      \
                                          reg |= RCU_AHB_CKSYS_DIV1;      \
                                          RCU_CFG0 = reg;                 \
                                      }                                   \
                                  }while(0)


Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Add a three-step frequency switching function in the system_gd32e502.c file for decreasing frequency stages.

V1.3.0:
none
 
V1.4.0:
								  
void SystemInit(void)
{
	......
	
    if(((RCU_CFG0 & RCU_CFG0_SCSS) == RCU_SCSS_PLL)){
        RCU_MODIFY_DE_3(0x100);
    }
	
	......
								  
}

Fix file:
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c

fix reason: 
Add a three-step frequency switching function in the system_gd32e502.c file for increasing frequency stages.

V1.3.0:
none
 
V1.4.0:
static void system_clock_24m_pll_irc8m(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x50);

	......	
}

static void system_clock_48m_pll_irc8m(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x50);

	......	
}

static void system_clock_72m_pll_irc8m(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x100);

	......	
}

static void system_clock_100m_pll_irc8m(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x100);

	......	
}

static void system_clock_24m_pll_hxtal(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x50);

	......	
}

static void system_clock_48m_pll_hxtal(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x50);

	......	
}

static void system_clock_72m_pll_hxtal(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x100);

	......	
}

static void system_clock_100m_pll_hxtal(void)
{
	......
	
    /* IRC8M is stable */
    /* AHB = SYSCLK/8 */
    RCU_CFG0 |= RCU_AHB_CKSYS_DIV8;

	......

    RCU_MODIFY_UP_3(0x100);

	......	
}
________________________________________________________________________________________________________________________

________________________Module FMC _______________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.h

fix reason:
Remove all function macros related to EPROM functions from the FMC standard library.

V1.3.0:
#define FMC_EPCNT                    REG32((FMC) + 0x00000058U)                         /*!< FMC EEPROM counter register */
#define FMC_WS_ERAMRDY               BIT(16)                                            /*!< EEPROM SRAM ready flag */
#define FMC_ECCCS_EPECCDET           BIT(29)                                            /*!< EEPROM two bits error detect flag *
#define FMC_EPCNT_EPCNT              BITS(0,31)                                         /*!< EEPROM erase counter */
#define FMC_WP1_EPWP                 BITS(16,23)                                        /*!< store OB_EPWP[7:0] of option bytes 0 block after system reset */

FMC_FLAG_EPECCDET = FMC_REGIDX_BIT(FMC_ECCCS_REG_OFFSET, 29U),                                          /*!< EEPROM two bits error detect flag */
FMC_INT_FLAG_EPECCDET = FMC_REGIDX_BIT2(FMC_ECCCS_REG_OFFSET, 25U, FMC_ECCCS_REG_OFFSET, 29U),          /*!< EEPROM two bits error detect interrupt flag */

#define EEPROM_SRAM_CMD              CTL1_SRAMCMD(3)                                    /*!< set EEPROM RAM mode */

/* option bytes 1 shared RAM init mode in FMC_OB1CS register */
#define OB1CS_EPLOAD(regval)         (BIT(15) & ((uint32_t)(regval) << 15))
#define OB1CS_EPLOAD_NOT_LOAD_EPDATA OB1CS_EPLOAD((uint16_t)0x00U)                      /*!< shared SRAM is not loaded with valid EEPROM data during FMC reset */
#define OB1CS_EPLOAD_LOAD_EPDATA     OB1CS_EPLOAD((uint16_t)0x01U)                      /*!< shared SRAM is loaded with valid EEPROM data during FMC reset */

/* option bytes 1 EEPROM size in FMC_OB1CS register */
#define OB1CS_EPSIZE(regval)         (BITS(8, 11) & ((uint32_t)(regval) << 8))
#define OB1CS_EPSIZE_NONE            OB1CS_EPSIZE((uint8_t)0x0FU)                      /*!< no EEPROM */
#define OB1CS_EPSIZE_4K              OB1CS_EPSIZE((uint8_t)0x08U)                      /*!< 4KB EEPROM, 384K flash or 256K flash */
#define OB1CS_EPSIZE_2K              OB1CS_EPSIZE((uint8_t)0x04U)                      /*!< 2KB EEPROM, 128K flash */
#define OB1CS_EPSIZE_1K              OB1CS_EPSIZE((uint8_t)0x02U)                      /*!< 1KB EEPROM, 64K flash */

/* option bytes 1 shared RAM init mode in FMC_OB1CS register */
#define OB1CS_EPLOAD(regval)         (BIT(15) & ((uint32_t)(regval) << 15))
#define OB1CS_EPLOAD_NOT_LOAD_EPDATA OB1CS_EPLOAD((uint16_t)0x00U)                      /*!< shared SRAM is not loaded with valid EEPROM data during FMC reset */
#define OB1CS_EPLOAD_LOAD_EPDATA     OB1CS_EPLOAD((uint16_t)0x01U)                      /*!< shared SRAM is loaded with valid EEPROM data during FMC reset */

/* option bytes 1 EEPROM size in FMC_OB1CS register */
#define OB1CS_EPSIZE(regval)         (BITS(8, 11) & ((uint32_t)(regval) << 8))
#define OB1CS_EPSIZE_NONE            OB1CS_EPSIZE((uint8_t)0x0FU)                      /*!< no EEPROM */
#define OB1CS_EPSIZE_4K              OB1CS_EPSIZE((uint8_t)0x08U)                      /*!< 4KB EEPROM, 384K flash or 256K flash */
#define OB1CS_EPSIZE_2K              OB1CS_EPSIZE((uint8_t)0x04U)                      /*!< 2KB EEPROM, 128K flash */
#define OB1CS_EPSIZE_1K              OB1CS_EPSIZE((uint8_t)0x02U)                      /*!< 1KB EEPROM, 64K flash */

/* 384K flash or 256K flash */
#define OB1CS_EFALC(regval)          (BITS(4, 7) & ((uint32_t)(regval) << 4))
#define OB1CS_DF_64K_EF_0K           OB1CS_EFALC((uint8_t)0x00U)                        /*!< data flash size is 64KB, EEPROM backup size is 0KB */
#define OB1CS_DF_48K_EF_16K          OB1CS_EFALC((uint8_t)0x03U)                        /*!< data flash size is 48KB, EEPROM backup size is 16KB */
#define OB1CS_DF_32K_EF_32K          OB1CS_EFALC((uint8_t)0x04U)                        /*!< data flash size is 32KB, EEPROM backup size is 32KB */
#define OB1CS_DF_16K_EF_48K          OB1CS_EFALC((uint8_t)0x05U)                        /*!< data flash size is 16KB, EEPROM backup size is 48KB */
#define OB1CS_DF_0K_EF_64K           OB1CS_EFALC((uint8_t)0x08U)                        /*!< data flash size is 0KB, EEPROM backup size is 64KB */
#define OB1CS_DF_EF_INVALID          OB1CS_EFALC((uint8_t)0x0FU)                        /*!< data flash and EEPROM backup are invalid */

/* 128K flash */
#define OB1CS_DF_32K_EF_0K           OB1CS_EFALC((uint8_t)0x01U)                        /*!< data flash size is 32KB, EEPROM backup size is 0KB */
#define OB1CS_DF_8K_EF_24K           OB1CS_EFALC((uint8_t)0x06U)                        /*!< data flash size is 8KB, EEPROM backup size is 24KB */
#define OB1CS_DF_0K_EF_32K           OB1CS_EFALC((uint8_t)0x09U)                        /*!< data flash size is 0KB, EEPROM backup size is 32KB */
#define OB1CS_DF_16K_EF_16K          OB1CS_EFALC((uint8_t)0x0BU)                        /*!< data flash size is 16KB, EEPROM backup size is 16KB */
#define OB1CS_DF_24K_EF_8K           OB1CS_EFALC((uint8_t)0x0CU)                        /*!< data flash size is 24KB, EEPROM backup size is 8KB */
/* 64K flash */
#define OB1CS_DF_16K_EF_0K           OB1CS_EFALC((uint8_t)0x02U)                        /*!< data flash size is 16KB, EEPROM backup size is 0KB */
#define OB1CS_DF_4K_EF_12K           OB1CS_EFALC((uint8_t)0x07U)                        /*!< data flash size is 4KB, EEPROM backup size is 12KB */
#define OB1CS_DF_0K_EF_16K           OB1CS_EFALC((uint8_t)0x0AU)                        /*!< data flash size is 0KB, EEPROM backup size is 16KB */
#define OB1CS_DF_8K_EF_8K            OB1CS_EFALC((uint8_t)0x0DU)                        /*!< data flash size is 8KB, EEPROM backup size is 8KB */
#define OB1CS_DF_12K_EF_4K           OB1CS_EFALC((uint8_t)0x0EU)                        /*!< data flash size is 12KB, EEPROM backup size is 4KB */

#define WP1_EPWP_OFFSET                 ((uint32_t)0x00000010U)               /*!< EPWP offset in FMC_WP1 register */
 
V1.4.0:
Remove all function macros related to EPROM functions from the FMC standard library.

Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.h

fix reason:
Add the function macros related to EPROM functions from the FMC standard library.

V1.3.0:
none

V1.4.0:
/* option bytes 1 extend flash block allocation in FMC_OB1CS register */
#define OB1CS_EFALC_EPSIZE(regval)   (BITS(4, 11) & ((uint32_t)(regval) << 4))
#define OB1CS_DF_INVALID             OB1CS_EFALC_EPSIZE((uint8_t)0xFFU)                 /*!< invalid configuration */
/* 384K flash or 256K flash */
#define OB1CS_DF_64K                 OB1CS_EFALC_EPSIZE((uint8_t)0xF0U)                 /*!< data flash size is 64KB */

Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.h

fix reason:
Remove all API interfaces related to EPROM functions from the FMC standard library.

V1.3.0:
/* program a word at the corresponding address in EEPROM */
fmc_state_enum eeprom_word_program(uint32_t address, uint32_t data);
/* read a word at the corresponding address in EEPROM */
uint32_t eeprom_word_read(uint32_t address);
/* get the value of FMC option bytes EPWP in FMC_WP1 register */
uint8_t ob_ep_write_protection_get(void);
/* configure the EPLOAD value of option bytes 1 loaded after the system reset */
fmc_state_enum ob1_epload_config(uint32_t epload)
/* get EEPROM backup size in byte unit */
uint32_t eeprom_backup_size_get(void);
/* get EEPROM size in byte unit */
uint32_t eeprom_size_get(void);

V1.4.0:
Remove all API interfaces related to EPROM functions from the FMC standard library.

Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.h

fix reason:
Due to the removal of the hardware EEPROM function, modify the value of the macro definition.

V1.3.0:
#define ECCCS_FLAG_MASK                 ((uint32_t)0xEC000000U)               /*!< flag mask in ECCCS register */

V1.4.0:
#define ECCCS_FLAG_MASK                 ((uint32_t)0xCC000000U)               /*!< flag mask in ECCCS register */

Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.c
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_fmc.h

fix reason:
Due to the removal of the hardware EEPROM function, modify the API interface.

V1.3.0:
void fmc_sram_mode_config(fmc_sram_mode_enum sram_mode)
{
    fmc_sram_mode_enum curr_mode;

    curr_mode = fmc_sram_mode_get();
    FMC_CTL1 &= ~FMC_CTL1_SRAMCMD;
    if((EEPROM_SRAM_MODE == sram_mode) && (EEPROM_SRAM_MODE != curr_mode)) {
        /* set shared SRAM to EEPROM SRAM mode*/
        FMC_CTL1 |= EEPROM_SRAM_CMD;
        fmc_sram_mode_ready_wait(FMC_WS_ERAMRDY);
    } else if((BASIC_SRAM_MODE == sram_mode) && (BASIC_SRAM_MODE != curr_mode)) {
        /* set shared SRAM to basic SRAM mode*/
        FMC_CTL1 |= BASIC_SRAM_CMD;
        fmc_sram_mode_ready_wait(FMC_WS_BRAMRDY);
    } else if((FASTPG_SRAM_MODE == sram_mode) && (FASTPG_SRAM_MODE != curr_mode)) {
        /* set shared SRAM to fast program SRAM mode*/
        FMC_CTL1 |= FASTPG_SRAM_CMD;
        fmc_sram_mode_ready_wait(FMC_WS_PRAMRDY);
    } else {
        /* illegal parameters */
    }
}

V1.4.0:
void fmc_sram_mode_config(fmc_sram_mode_enum sram_mode)
{
    fmc_sram_mode_enum curr_mode;

    curr_mode = fmc_sram_mode_get();
    FMC_CTL1 &= ~FMC_CTL1_SRAMCMD;

    if((BASIC_SRAM_MODE == sram_mode) && (BASIC_SRAM_MODE != curr_mode)) {
        /* set shared SRAM to basic SRAM mode*/
        FMC_CTL1 |= BASIC_SRAM_CMD;
        fmc_sram_mode_ready_wait(FMC_WS_BRAMRDY);
    } else if((FASTPG_SRAM_MODE == sram_mode) && (FASTPG_SRAM_MODE != curr_mode)) {
        /* set shared SRAM to fast program SRAM mode*/
        FMC_CTL1 |= FASTPG_SRAM_CMD;
        fmc_sram_mode_ready_wait(FMC_WS_PRAMRDY);
    } else {
        /* illegal parameters */
    }
}

fix reason:
Due to the removal of the hardware EEPROM function, modify the API interface.

V1.3.0:
fmc_sram_mode_enum fmc_sram_mode_get(void)
{
    fmc_sram_mode_enum sram_mode;

    if(0U != (FMC_WS & FMC_WS_ERAMRDY)) {
        /* SRAM is in EEPROM SRAM mode*/
        sram_mode = EEPROM_SRAM_MODE;
    } else if(0U != (FMC_WS & FMC_WS_BRAMRDY)) {
        /* SRAM is in basic SRAM mode*/
        sram_mode = BASIC_SRAM_MODE;
    } else if(0U != (FMC_WS & FMC_WS_PRAMRDY)) {
        /* SRAM is in fast program SRAM mode*/
        sram_mode = FASTPG_SRAM_MODE;
    } else {
        sram_mode = NO_SRAM_MODE;
    }

    return sram_mode;
}

V1.4.0:
fmc_sram_mode_enum fmc_sram_mode_get(void)
{
    fmc_sram_mode_enum sram_mode;

    if(0U != (FMC_WS & FMC_WS_BRAMRDY)) {
        /* SRAM is in basic SRAM mode*/
        sram_mode = BASIC_SRAM_MODE;
    } else if(0U != (FMC_WS & FMC_WS_PRAMRDY)) {
        /* SRAM is in fast program SRAM mode*/
        sram_mode = FASTPG_SRAM_MODE;
    } else {
        sram_mode = NO_SRAM_MODE;
    }

    return sram_mode;
}

fix reason:
Due to the removal of the hardware EEPROM function, modify the API interface.

V1.3.0:
fmc_state_enum ob_write_protection_enable(fmc_area_enum wp_area, uint32_t ob_wp)
{
    uint32_t i;
    uint32_t op_byte[OB_WORD_CNT] = {0U};
    fmc_state_enum fmc_state;

    /* check the option bytes security protection value */
    if(OB_OBSTAT_PLEVEL_HIGH == ob_plevel_get()) {
        return FMC_OB_HSPC;
    }

    /* read option bytes */
    for(i = 0U; i < OB_WORD_CNT; i++) {
        op_byte[i] = OP_BYTE(i);
    }

    ob_wp = (uint32_t)(~ob_wp);
    if(BANK0_AREA == wp_area) {
        /* configure write protection to main flash bank0 area */
        op_byte[2] &= (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
        op_byte[3] &= ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
    } else if(BANK1_AREA == wp_area) {
        /* configure write protection to main flash bank1 area */
        op_byte[4] &= (uint32_t)((ob_wp & LOW_8BITS_MASK) | HIGH_16BITS_MASK);
    } else if(DATA_FLASH_AREA == wp_area) {
        /* configure write protection to data flash area */
        op_byte[4] &= (uint32_t)(((ob_wp & LOW_8BITS_MASK) << 16U) | LOW_16BITS_MASK);
    } else if(EEPROM_AREA == wp_area) {
        /* configure write protection to EEPROM area */
        op_byte[5] &= (uint32_t)(ob_wp & LOW_8BITS_MASK);
    } else {
        /* illegal parameters */
    }

    /* wait for the FMC ready */
    fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

    if(FMC_READY == fmc_state) {
        /* start erase the option bytes */
        FMC_CTL1 |= FMC_CTL1_OB0ER;
        FMC_CTL1 |= FMC_CTL1_START;

        /* wait for the FMC ready */
        fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

        if(FMC_READY == fmc_state) {
            /* reset the OB0ER bit */
            FMC_CTL1 &= ~FMC_CTL1_OB0ER;

            /* enable the option bytes programming */
            FMC_CTL1 |= FMC_CTL1_OB0PG;

            /* write option bytes */
            for(i = 0U; i < OB_DOUBLEWORD_CNT; i++) {
                OP_BYTE(i * 2U) = op_byte[i * 2U];
                OP_BYTE(i * 2U + 1U) = op_byte[i * 2U + 1U];
                fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
                if(FMC_READY != fmc_state) {
                    break;
                }
            }
            /* wait for the FMC ready */
            fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

            /* reset the OB0PG bit */
            FMC_CTL1 &= ~FMC_CTL1_OB0PG;
        } else {
            /* reset the OB0ER bit */
            FMC_CTL1 &= ~FMC_CTL1_OB0ER;
        }
    }

    /* return the FMC state */
    return fmc_state;
}

V1.4.0:
fmc_state_enum ob_write_protection_enable(fmc_area_enum wp_area, uint32_t ob_wp)
{
    uint32_t i;
    uint32_t op_byte[OB_WORD_CNT] = {0U};
    fmc_state_enum fmc_state;

    /* check the option bytes security protection value */
    if(OB_OBSTAT_PLEVEL_HIGH == ob_plevel_get()) {
        return FMC_OB_HSPC;
    }

    /* read option bytes */
    for(i = 0U; i < OB_WORD_CNT; i++) {
        op_byte[i] = OP_BYTE(i);
    }

    ob_wp = (uint32_t)(~ob_wp);
    if(BANK0_AREA == wp_area) {
        /* configure write protection to main flash bank0 area */
        op_byte[2] &= (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
        op_byte[3] &= ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
    } else if(BANK1_AREA == wp_area) {
        /* configure write protection to main flash bank1 area */
        op_byte[4] &= (uint32_t)((ob_wp & LOW_8BITS_MASK) | HIGH_16BITS_MASK);
    } else if(DATA_FLASH_AREA == wp_area) {
        /* configure write protection to data flash area */
        op_byte[4] &= (uint32_t)(((ob_wp & LOW_8BITS_MASK) << 16U) | LOW_16BITS_MASK);
    } else {
        /* illegal parameters */
    }

    /* wait for the FMC ready */
    fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

    if(FMC_READY == fmc_state) {
        /* start erase the option bytes */
        FMC_CTL1 |= FMC_CTL1_OB0ER;
        FMC_CTL1 |= FMC_CTL1_START;

        /* wait for the FMC ready */
        fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

        if(FMC_READY == fmc_state) {
            /* reset the OB0ER bit */
            FMC_CTL1 &= ~FMC_CTL1_OB0ER;

            /* enable the option bytes programming */
            FMC_CTL1 |= FMC_CTL1_OB0PG;

            /* write option bytes */
            for(i = 0U; i < OB_DOUBLEWORD_CNT; i++) {
                OP_BYTE(i * 2U) = op_byte[i * 2U];
                OP_BYTE(i * 2U + 1U) = op_byte[i * 2U + 1U];
                fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
                if(FMC_READY != fmc_state) {
                    break;
                }
            }
            /* wait for the FMC ready */
            fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

            /* reset the OB0PG bit */
            FMC_CTL1 &= ~FMC_CTL1_OB0PG;
        } else {
            /* reset the OB0ER bit */
            FMC_CTL1 &= ~FMC_CTL1_OB0ER;
        }
    }

    /* return the FMC state */
    return fmc_state;
}

fix reason:
Due to the removal of the hardware EEPROM function, modify the API interface.

V1.3.0:
fmc_state_enum ob1_eeprom_parameter_config(uint32_t efalc, uint32_t epsize)
{
    uint32_t reg;
    fmc_state_enum fmc_state;

    /* check the option bytes security protection value */
    if(0U != (FMC_OB1CS & FMC_OB1CS_OB1LK)) {
        return FMC_OB1_LK;
    }
    /* configure the EFALC and EPSIZE */
    reg = FMC_OB1CS;
    reg &= ~FMC_OB1CS_EFALC;
    reg |= efalc;
    reg &= ~FMC_OB1CS_EPSIZE;
    reg |= epsize;

    /* wait for the FMC ready */
    fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

    if(FMC_READY == fmc_state) {
        /* write the value to EPSIZE and EFALC in FMC_OB1CS register */
        FMC_OB1CS = reg;

        /* set the OB1START bit */
        FMC_OB1CS |= FMC_OB1CS_OB1START;

        /* wait for the FMC ready */
        fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
        /* reset the OB1START bit */
        FMC_OB1CS &= ~FMC_OB1CS_OB1START;
    }

    /* return the FMC state */
    return fmc_state;
}

V1.4.0:
fmc_state_enum ob1_parameter_config(uint32_t dflash_size)
{
    uint32_t reg;
    fmc_state_enum fmc_state;

    /* check the option bytes security protection value */
    if(0U != (FMC_OB1CS & FMC_OB1CS_OB1LK)) {
        return FMC_OB1_LK;
    }
    /* configure the EFALC and EPSIZE */
    reg = FMC_OB1CS;
    reg &= ~FMC_OB1CS_EPLOAD;
    reg &= ~FMC_OB1CS_EFALC;
    reg &= ~FMC_OB1CS_EPSIZE;
    reg |= dflash_size;

    /* wait for the FMC ready */
    fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);

    if(FMC_READY == fmc_state) {
        /* write the value to EPSIZE and EFALC in FMC_OB1CS register */
        FMC_OB1CS = reg;

        /* set the OB1START bit */
        FMC_OB1CS |= FMC_OB1CS_OB1START;

        /* wait for the FMC ready */
        fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
        /* reset the OB1START bit */
        FMC_OB1CS &= ~FMC_OB1CS_OB1START;
    }

    /* return the FMC state */
    return fmc_state;
}

fix reason:
Due to the removal of the hardware EEPROM function, modify the API interface.

V1.3.0:
uint32_t dflash_size_get(void)
{
    uint32_t efalc_value;
    uint32_t dflash_size = 0U;

    /* get EFALC value in option bytes 1 */
    efalc_value = FMC_OB1CS & FMC_OB1CS_EFALC;

    switch(efalc_value) {
    case OB1CS_DF_64K_EF_0K:
        dflash_size = 64U * 0x400U;
        break;
    case OB1CS_DF_48K_EF_16K:
        dflash_size = 48U * 0x400U;
        break;
    case OB1CS_DF_32K_EF_32K:
        dflash_size = 32U * 0x400U;
        break;
    case OB1CS_DF_16K_EF_48K:
        dflash_size = 16U * 0x400U;
        break;
    case OB1CS_DF_0K_EF_64K:
        dflash_size = 0x00000000U;
        break;
    case OB1CS_DF_EF_INVALID:
        dflash_size = 0xFFFFFFFFU;
        break;
    case OB1CS_DF_32K_EF_0K:
        dflash_size = 32U * 0x400U;
        break;
    case OB1CS_DF_8K_EF_24K:
        dflash_size = 8U * 0x400U;
        break;
    case OB1CS_DF_0K_EF_32K:
        dflash_size = 0x00000000U;
        break;
    case OB1CS_DF_16K_EF_16K:
        dflash_size = 16U * 0x400U;
        break;
    case OB1CS_DF_24K_EF_8K:
        dflash_size = 24U * 0x400U;
        break;
    case OB1CS_DF_16K_EF_0K:
        dflash_size = 16U * 0x400U;
        break;
    case OB1CS_DF_4K_EF_12K:
        dflash_size = 4U * 0x400U;
        break;
    case OB1CS_DF_0K_EF_16K:
        dflash_size = 0x00000000U;
        break;
    case OB1CS_DF_8K_EF_8K:
        dflash_size = 8U * 0x400U;
        break;
    case OB1CS_DF_12K_EF_4K:
        dflash_size = 12U * 0x400U;
        break;
    default:
        break;
    }

    return dflash_size;
}

V1.4.0:
uint32_t dflash_size_get(void)
{
    uint32_t value;
    uint32_t dflash_size = 0U;

    /* get EFALC & EPSIZE value in option bytes 1 */
    value = FMC_OB1CS & FMC_OB1CS_EFALC;
    value |= FMC_OB1CS & FMC_OB1CS_EPSIZE;

    switch(value) {
    case OB1CS_DF_64K:
        dflash_size = 64U * 0x400U;
        break;
    case OB1CS_DF_INVALID:
        dflash_size = 0xFFFFFFFFU;
        break;
    case OB1CS_DF_32K:
        dflash_size = 32U * 0x400U;
        break;
    case OB1CS_DF_16K:
        dflash_size = 16U * 0x400U;
        break;
    default:
        break;
    }

    return dflash_size;
}

Fix file:
../Examples/FMC/Data_flash_erase_program

fix reason:
Remove the EEPROM function in the GD32E502 series.

V1.3.0:
int main(void)
{
	.......
	
    /* configure the data flash size as 64k */
    if(0x10000 != dflash_size_get()){
        ob1_eeprom_parameter_config(OB1CS_DF_64K_EF_0K, OB1CS_EPSIZE_NONE);
        ob_reset();
    }
	
	.......

}
 
V1.4.0:
int main(void)
{
	.......
	
    /* configure the data flash size as 64k */
    if(0x10000 != dflash_size_get()){
        ob1_parameter_config(OB1CS_DF_64K);
        ob_reset();
    }
	
	.......

} 
__________________________________________________________________________________________________________________________

________________________Module CAN _______________________________________________________________________________________
Fix file:
../Examples/CAN/communication_classical_CAN/main.c
../Examples/CAN/communication_FDmode/main.c
../Examples/CAN/communication_Loopback/main.c
../Examples/CAN/Pretended_Networking_mode/main.c
fix reason:
The use of the CAN module clock source is restricted and should be referred to the errata.of GD32E502 series, PCLK2 is recommended

V1.3.0:
/* enable CAN clock */
rcu_can_clock_config(CAN0, RCU_CANSRC_PCLK2_DIV_2);
rcu_can_clock_config(CAN1, RCU_CANSRC_PCLK2_DIV_2);

V1.4.0:
/* enable CAN clock */
rcu_can_clock_config(CAN0, RCU_CANSRC_PCLK2);
rcu_can_clock_config(CAN1, RCU_CANSRC_PCLK2);

__________________________________________________________________________________________________________________________

______________________Module USART_________________________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_usart.c
fix reason:
Improve the robustness of the API interface. The API interface should add a judgment for the baud rate parameter being 0 to prevent the application layer from setting the baud rate parameter to 0, which would cause a divide-by-zero error.

V1.3.0:
void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval)
{

	......
	
    if(USART_CTL0(usart_periph) & USART_CTL0_OVSMOD) {
        /* oversampling by 8, configure the value of USART_BAUD */
        udiv = ((2U * uclk) + (baudval / 2U)) / baudval;
        intdiv = udiv & 0x0000fff0U;
        fradiv = (udiv >> 1U) & 0x00000007U;
        USART_BAUD(usart_periph) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
    } else {
        /* oversampling by 16, configure the value of USART_BAUD */
        udiv = (uclk + (baudval / 2U)) / baudval;
        intdiv = udiv & 0x0000fff0U;
        fradiv = udiv & 0x0000000fU;
        USART_BAUD(usart_periph) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
    }
	
	......
}
 
V1.4.0:
void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval)
{

	......
	
    if(baudval != 0U) {
        if(USART_CTL0(usart_periph) & USART_CTL0_OVSMOD) {
            /* oversampling by 8, configure the value of USART_BAUD */
            udiv = ((2U * uclk) + (baudval / 2U)) / baudval;
            intdiv = udiv & 0x0000fff0U;
            fradiv = (udiv >> 1U) & 0x00000007U;
            USART_BAUD(usart_periph) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
        } else {
            /* oversampling by 16, configure the value of USART_BAUD */
            udiv = (uclk + (baudval / 2U)) / baudval;
            intdiv = udiv & 0x0000fff0U;
            fradiv = udiv & 0x0000000fU;
            USART_BAUD(usart_periph) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
        }
    } else {
        /* do nothing */
    }
	
	......
}
__________________________________________________________________________________________________________________________

______________________Module CRC_________________________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_crc.c

fix reason:
Resolve the issue of API interfaces violating the MISRA C 2004 rule 17.4.

V1.3.0:
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
{
    uint8_t *data8;
    uint16_t *data16;
    uint32_t *data32;
    uint32_t index;

    if(INPUT_FORMAT_WORD == data_format) {
        data32 = (uint32_t *)array;
        for(index = 0U; index < size; index++) {
            REG32(CRC) = data32[index];
        }
    } else if(INPUT_FORMAT_HALFWORD == data_format) {
        data16 = (uint16_t *)array;
        for(index = 0U; index < size; index++) {
            REG16(CRC) = data16[index];
        }
    } else {
        data8 = (uint8_t *)array;
        for(index = 0U; index < size; index++) {
            REG8(CRC) = data8[index];
        }
    }

    return (CRC_DATA);
}

V1.4.0:
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
{
    uint32_t index;
    uint32_t data = (uint32_t)array;

    if(INPUT_FORMAT_WORD == data_format) {
        for(index = 0U; index < size; index++) {
            REG32(CRC) = *(uint32_t *)data;
            data += 4U;
        }
    } else if(INPUT_FORMAT_HALFWORD == data_format) {
        for(index = 0U; index < size; index++) {
            REG16(CRC) = *(uint16_t *)data;
            data += 2U;
        }
    } else {
        for(index = 0U; index < size; index++) {
            REG8(CRC) = *(uint8_t *)data;
            data += 1U;
        }
    }

    return (CRC_DATA);
}
__________________________________________________________________________________________________________________________




******************* V1.3.0 2024-07-30 ******************************************************************************************
______________________Common______________________________________________________________________________________________
Fix file:
../Template/main.c
fix reason: 
Serial port printing function adapted for the GCC environment.
V1.2.0:
none 
V1.3.0:
int __io_putchar(int ch)
{
    usart_data_transmit(EVAL_COM, (uint8_t)ch);
    while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
    return ch;
} 

Fix file:
../Template/gd32e502_it.c
fix reason:
SRAM ECC single-bit errors will not trigger an NMI exception.
V1.2.0:
void NMI_Handler(void)
{
    if(SET == syscfg_interrupt_flag_get(SYSCFG_INT_FLAG_SRAMECCMERR)) {
        SRAM_ECC_ERROR_HANDLE("SRAM multi-bits non-correction ECC error\r\n");
    }else if(SET == syscfg_interrupt_flag_get(SYSCFG_INT_FLAG_SRAMECCSERR)) {
        SRAM_ECC_ERROR_HANDLE("SRAM single bit correction ECC error\r\n");
    }else if(SET == syscfg_interrupt_flag_get(SYSCFG_INT_FLAG_FLASHECCERR)){
        FLASH_ECC_ERROR_HANDLE("FLASH ECC error\r\n");
    }else{
        /* if NMI exception occurs, go to infinite loop */
        /* HXTAL clock monitor NMI error or NMI pin error */
        while(1) {
        }
    }
}
V1.3.0:
void NMI_Handler(void)
{
    if(SET == syscfg_interrupt_flag_get(SYSCFG_INT_FLAG_SRAMECCMERR)) {
        SRAM_ECC_ERROR_HANDLE("SRAM multi-bits non-correction ECC error\r\n");
    } else if(SET == syscfg_interrupt_flag_get(SYSCFG_INT_FLAG_FLASHECCERR)) {
        FLASH_ECC_ERROR_HANDLE("FLASH ECC error\r\n");
    } else {
        /* if NMI exception occurs, go to infinite loop */
        /* HXTAL clock monitor NMI error or NMI pin error */
        while(1) {
        }
    }
}

Fix file:
../Template/gd32e502_it.c
../Template/gd32e502_it.h
fix reason:
Add FPU and SRAMECC single-bit error interrupt handlers, with these interrupts being enabled by default to prevent unexpected 
interrupts caused by application code and to provide user notifications.
V1.2.0:
none
V1.3.0:
void FPU_IRQHandler(void)
{
    /* if FPU error occurs, go to infinite loop */
    while(1) {
    }
}

void SRAMC_ECCSE_IRQHandler(void)
{
    if(SET == syscfg_interrupt_flag_get(SYSCFG_INT_FLAG_SRAMECCSERR)) {
        SRAM_ECC_ERROR_HANDLE("SRAM single bit ECC error\r\n");
    }
}
 
Fix file:
../Template/main.c
../Firmware/CMSIS/GD/GD32E502/Source/system_gd32e502.c
../Firmware/CMSIS/GD/GD32E502/Include/system_gd32e502.h
fix reason: 
Add firmware library version printing function.
V1.2.0:
none 
V1.3.0:
#ifdef __FIRMWARE_VERSION_DEFINE
    fw_ver = gd32e502_firmware_version_get();
    /* print firmware version */
    printf("\r\nGD32E502 series firmware version: V%d.%d.%d", (uint8_t)(fw_ver >> 24), (uint8_t)(fw_ver >> 16), (uint8_t)(fw_ver >> 8));
#endif /* __FIRMWARE_VERSION_DEFINE */
__________________________________________________________________________________________________________________________

________________________Module CAN _______________________________________________________________________________________
Fix file:
../Examples/CAN/communication_classical_CAN/main.c
../Examples/CAN/communication_FDmode/main.c
../Examples/CAN/communication_Loopback/main.c
../Examples/CAN/Pretended_Networking_mode/main.c
fix reason:
When the CAN TX pin is not pulled up with a resistor between it and the transceiver, prevent the CAN TX pin from being pulled down.
V1.2.0:
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6); 
V1.3.0:
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_13);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6); 

Fix file:
../Examples/CAN/communication_classical_CAN/main.c
../Examples/CAN/communication_FDmode/main.c
../Examples/CAN/Pretended_Networking_mode/main.c
fix reason:
During the transmission process, data is moved from the mailbox to the internal buffer area after being written, and then sent to the bus from the internal buffer area. When the bus load is too high and there are no restrictions on the sending operation, directly writing to the transmission mailbox again before the move-out operation is completed can cause the state machine to incorrectly unlock the receive mailbox.
V1.2.0:
none
V1.3.0:
if((RESET == can_tx_state) || (SET == can_flag_get(CAN1, CAN_FLAG_MB1))){
} 
__________________________________________________________________________________________________________________________

______________________PMU_________________________________________________________________________________________________
Fix file:
../Firmware/GD32E502_standard_peripheral/Source/gd32e502_pmu.c
fix reason:
Turn off all interrupts before entering DeepSleep.
V1.2.0:
if(WFI_CMD == deepsleepmodecmd) {
    __WFI();
} else {
    __SEV();
    __WFE();
    __WFE();
} 
V1.3.0:
reg_snap[0] = REG32(0xE000E010U);
reg_snap[1] = REG32(0xE000E100U);
reg_snap[2] = REG32(0xE000E104U);
reg_snap[3] = REG32(0xE000E108U);

REG32(0xE000E010U) &= 0x00010004U;
REG32(0xE000E180U)  = 0XFDFFF835U;
REG32(0xE000E184U)  = 0XBFF5FC1FU;
REG32(0xE000E188U)  = 0xFFFFFFFFU;

if(WFI_CMD == deepsleepmodecmd) {
    __WFI();
} else {
    __SEV();
    __WFE();
    __WFE();
}

REG32(0xE000E010U) = reg_snap[0];
REG32(0xE000E100U) = reg_snap[1];
REG32(0xE000E104U) = reg_snap[2];
REG32(0xE000E108U) = reg_snap[3]; 
__________________________________________________________________________________________________________________________
